<script setup lang="ts">
import type { AppConfig } from '@shared/types/'
import { Loading } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useAppStore } from '../stores/app'

const appStore = useAppStore()
const activeTab = ref('basic')
const saving = ref(false)
// 预览条数上限：避免一次性渲染超大文本
const POOL_PREVIEW_LIMIT = 100
// 顶层池按需编辑
const rotateErrorsText = ref('')

// 本地配置副本 - 初始为空，将从后端加载默认配置
const localConfig = reactive<{ value: AppConfig | null }>({ value: null })
// 比较是否有未保存更改（忽略 _ 前缀的临时字段）
function stripTransient(obj: any): any {
  if (obj === null || typeof obj !== 'object')
    return obj
  if (Array.isArray(obj))
    return obj.map(stripTransient)
  const out: any = {}
  for (const k of Object.keys(obj)) {
    if (k.startsWith('_'))
      continue
    out[k] = stripTransient((obj as any)[k])
  }
  return out
}
const isDirty = computed(() => {
  try {
    if (!localConfig.value || !appStore.config)
      return false
    const a = stripTransient(JSON.parse(JSON.stringify(localConfig.value)))
    const b = stripTransient(JSON.parse(JSON.stringify(appStore.config)))
    return JSON.stringify(a) !== JSON.stringify(b)
  }
  catch { return false }
})

// 方法
async function loadConfig() {
  try {
    await appStore.loadConfig()
    if (appStore.config) {
      // 深拷贝，避免与 store 共享嵌套引用导致 isDirty 恒为 false
      localConfig.value = JSON.parse(JSON.stringify(appStore.config))
    }
    ElMessage.success('配置已加载')
  }
  catch (error) {
    console.error('加载配置失败:', error)
    ElMessage.error('加载配置失败')
  }
}

async function saveConfig() {
  try {
    if (!localConfig.value) {
      ElMessage.error('配置未初始化')
      return
    }
    saving.value = true

    // 若编辑弹窗打开，先把弹窗中的未确认修改合并到 localConfig
    try {
      commitPendingEditToLocal()
    }
    catch {}

    // 将 reactive 对象转换为普通对象以避免克隆问题
    const plainConfig = JSON.parse(JSON.stringify(localConfig.value))
    // 预处理：仅处理 providers 的池编辑
    try {
      const providers = (plainConfig?.proxy?.providers || []) as any[]
      if (Array.isArray(providers)) {
        providers.forEach((p) => {
          const hasPoolText = typeof (p as any)._poolText === 'string'
          const txt = hasPoolText ? String((p as any)._poolText) : ''
          // 新UI不再使用折叠编辑开关，若 _poolText 非空则视为用户输入，保存为数组
          if (hasPoolText && txt.trim().length > 0) {
            const arr = txt.split(/\r?\n|,/).map((s: string) => s.trim()).filter(Boolean)
            p.pool = arr
          }
          delete p._poolText
          delete p._poolPreviewText
          delete p._poolCount
          delete p._poolEditing
          if (p?.auth && !p.auth.username && !p.auth.password)
            delete p.auth
        })
      }
    }
    catch {}
    await appStore.updateConfig(plainConfig)
    ElMessage.success('配置已保存')
  }
  catch (error) {
    console.error('保存配置失败:', error)
    const msg = (error instanceof Error ? error.message : String(error)) || '保存配置失败'
    ElMessage.error(msg)
  }
  finally {
    saving.value = false
  }
}

// 注意：函数定义位置将在编辑弹窗定义之后（见下方），以避免“使用前定义”警告

async function resetConfig() {
  try {
    await ElMessageBox.confirm('确定要重置所有配置吗？此操作不可撤销。', '确认重置', {
      type: 'warning',
    })

    // 调用后端重置接口
    const result = await window.api.config.reset()
    if (result.success) {
      // 重新加载配置
      await loadConfig()
      ElMessage.success('配置已重置为默认值')
    }
    else {
      ElMessage.error(result.error || '重置配置失败')
    }
  }
  catch {
    // 用户取消
  }
}

// 初始化配置数据
async function initializeConfig() {
  try {
    // 首先尝试从 store 获取配置
    if (appStore.config) {
      // 深拷贝，避免与 store 共享嵌套引用导致 isDirty 恒为 false
      localConfig.value = JSON.parse(JSON.stringify(appStore.config))
    }
    else {
      // 如果 store 中没有配置，则加载配置
      await loadConfig()
    }
  }
  catch (error) {
    console.error('初始化配置失败:', error)
    ElMessage.error('初始化配置失败')
  }
}

// ===== 代理池/轮换错误 文本<->数组 同步 =====

// 顶层池概念已移除，这里仅保留轮换错误文本同步

watch(() => localConfig.value?.proxy?.rotate_on_errors, (arr) => {
  try {
    rotateErrorsText.value = (arr || []).join('\n')
  }
  catch {}
}, { deep: true, immediate: true })

watch(rotateErrorsText, (text) => {
  try {
    if (!localConfig.value?.proxy)
      return
    const arr = String(text || '')
      .split(/\r?\n|,/) // 支持换行或逗号分隔
      .map(s => s.trim())
      .filter(Boolean)
    localConfig.value.proxy.rotate_on_errors = arr
  }
  catch {}
})

// 生命周期
onMounted(async () => {
  await initializeConfig()
  await loadBlacklist()
  await loadQuotaMarks()
})

async function openLogsDir() {
  try {
    const res = await (window as any).api?.system?.getLogsPath()
    if (res?.success && res.path) {
      await (window as any).api?.system?.openPath(res.path)
    }
    else {
      ElMessage.error(res?.error || '无法获取日志目录')
    }
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

// 已移除强制日期范围配置（交由预约页面与预约数据控制）

// Providers 的 _poolText 初始化与同步
watch(() => localConfig.value?.proxy?.providers, (arr) => {
  try {
    const providers = arr as any[]
    if (Array.isArray(providers)) {
      providers.forEach((p) => {
        if (!p)
          return
        // 统计与预览：仅生成前 N 条，避免 2w+ 条字符串拼接导致卡顿
        const poolArr = Array.isArray(p.pool) ? p.pool : []
        ;(p as any)._poolCount = poolArr.length
        ;(p as any)._poolPreviewText = poolArr.slice(0, POOL_PREVIEW_LIMIT).join('\n')
        // 初始不进入编辑模式，且不保存完整文本到 _poolText（保持为空以节省内存）
        if ((p as any)._poolEditing !== true)
          (p as any)._poolText = ''
      })
    }
  }
  catch {}
}, { deep: true, immediate: true })

// 新增代理：弹窗模式
const addDialog = reactive({ visible: false, model: { vendor: 'webshare', type: 'datacenter', protocol: 'http', account: '', api_key: '', is_free: false } as any })
function openAddProviderDialog() {
  addDialog.model = { vendor: 'webshare', type: 'datacenter', protocol: 'http', account: '', api_key: '', is_free: false }
  addDialog.visible = true
}
async function confirmAddProvider() {
  try {
    if (!localConfig.value)
      return
    const list = localConfig.value.proxy.providers || []
    const id = `provider_${(list.length + 1)}`
    const base: any = {
      id,
      vendor: (addDialog.model.vendor || 'webshare').toLowerCase(),
      type: addDialog.model.type || 'datacenter',
      protocol: addDialog.model.protocol || 'http',
      enabled: true,
      auth: { username: '', password: '' },
      pool: [],
      _poolText: '',
    }
    if (base.vendor === 'webshare') {
      base.account = addDialog.model.account || ''
      base.api_key = addDialog.model.api_key || ''
      base.is_free = !!addDialog.model.is_free
      updateWebshareLabel(base)
    }
    else {
      // 自定义供应商：校验必填
      const user = String(addDialog.model.proxyUser || '').trim()
      const pass = String(addDialog.model.proxyPass || '').trim()
      const poolText = String(addDialog.model.poolText || '').trim()
      if (!user || !pass || !poolText) {
        ElMessage.error('自定义供应商需填写 代理帐号/代理密码/IP池')
        return
      }
      base.auth = { username: user, password: pass }
      base.pool = poolText.split(/\r?\n|,/).map((s: string) => s.trim()).filter(Boolean)
      base.label = '自定义代理'
    }
    const nextList = [...list, base]
    // 立即持久化，保证后续“拉取代理池”能找到 provider
    const payload = JSON.parse(JSON.stringify({ proxy: { providers: cleanProvidersForSave(nextList) } }))
    await appStore.updateConfig(payload as any)
    localConfig.value.proxy.providers = nextList
    addDialog.visible = false
    ElMessage.success('已新增代理')
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

function removeProvider(idx: number) {
  if (!localConfig.value?.proxy?.providers)
    return
  const list = [...localConfig.value.proxy.providers]
  // 确保移除后至少保持数组结构
  list.splice(idx, 1)
  localConfig.value.proxy.providers = list
}

// 归一化后的 providers 列表：保证每项都存在 auth 对象，避免 v-model 报错
const providersList = computed({
  get() {
    const list = (localConfig.value?.proxy?.providers || []) as any[]
    list.forEach((p) => {
      if (!p)
        return
      if (!p.auth)
        p.auth = { username: '', password: '' }
      if (typeof p.auth.username !== 'string')
        p.auth.username = ''
      if (typeof p.auth.password !== 'string')
        p.auth.password = ''
    })
    return list
  },
  set(val: any[]) {
    if (!localConfig.value)
      return
    localConfig.value.proxy.providers = val as any
  },
})

// 多服务商：筛选 + 排序(付费置顶) + 分页 + 折叠控制
const providerFilter = ref('')
const activeProviderId = ref<string | null>(null)
const providerPageSize = ref(5)
const providerCurrentPage = ref(1)
const providersFiltered = computed(() => {
  const list = (providersList.value || []) as any[]
  const q = providerFilter.value.trim().toLowerCase()
  const filtered = !q
    ? list
    : list.filter((p: any) => (p?.id || '').toLowerCase().includes(q) || (p?.label || '').toLowerCase().includes(q))
  // 付费置顶：is_free === true 视为免费，其它视为付费
  const paidScore = (p: any) => (p && p.is_free === true ? 1 : 0) // 0=付费,1=免费
  const getName = (p: any) => String(p?.label || p?.id || '').toLowerCase()
  return [...filtered].sort((a: any, b: any) => {
    const s = paidScore(a) - paidScore(b)
    if (s !== 0)
      return s
    return getName(a) < getName(b) ? -1 : getName(a) > getName(b) ? 1 : 0
  })
})
const providersPaged = computed(() => {
  const start = Math.max(0, (providerCurrentPage.value - 1) * providerPageSize.value)
  const end = start + providerPageSize.value
  return providersFiltered.value.slice(start, end)
})
// 过滤或页面大小变化时，重置到第1页，并默认收起
watch([providersFiltered, providerPageSize], () => {
  providerCurrentPage.value = 1
  activeProviderId.value = null
})

// ===== 代理校验与黑名单管理 =====
const validating = ref(false)
const blacklist = ref<any[]>([])
const loadingProviderId = ref<string | null>(null)
const statsLoadingProviderId = ref<string | null>(null)

// 表格启用开关快捷操作
async function onToggleProvider(row: any, idx: number, val: boolean) {
  try {
    if (!localConfig.value?.proxy?.providers)
      return
    const list = [...(localConfig.value.proxy.providers as any[])]
    const target = list[idx]
    if (!target)
      return
    target.enabled = !!val
    const payload = JSON.parse(JSON.stringify({ proxy: { providers: cleanProvidersForSave(list) } }))
    await appStore.updateConfig(payload as any)
    localConfig.value.proxy.providers = list
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

// 编辑弹窗
const editDialog = reactive({ visible: false, index: -1 as number, model: {} as any })
function openEditProvider(row: any, index: number) {
  try {
    editDialog.index = index
    const cloned = JSON.parse(JSON.stringify(row || {}))
    // 回填池到文本，便于立即可见/编辑
    ;(cloned as any)._poolText = Array.isArray(cloned.pool) ? cloned.pool.join('\n') : ''
    // 确保 auth 结构存在，避免 v-model 报错
    if (!cloned.auth)
      cloned.auth = { username: '', password: '' }
    if (typeof cloned.auth.username !== 'string')
      cloned.auth.username = ''
    if (typeof cloned.auth.password !== 'string')
      cloned.auth.password = ''
    editDialog.model = cloned
    editDialog.visible = true
  }
  catch {}
}
async function confirmEditProvider() {
  try {
    if (!localConfig.value?.proxy?.providers)
      return
    const list = [...(localConfig.value.proxy.providers as any[])]
    const i = editDialog.index
    if (i < 0 || i >= list.length)
      return
    const next = JSON.parse(JSON.stringify(editDialog.model || {}))
    // 同步 _poolText 到数组
    if (typeof (next as any)._poolText === 'string') {
      const txt = String((next as any)._poolText || '')
      const arr = txt
        .split(/\r?\n|,/)
        .map((s: string) => s.trim())
        .filter(Boolean)
      next.pool = arr
      delete (next as any)._poolText
    }
    // 自定义供应商时确保必要字段
    if ((String(next.vendor || '').toLowerCase() === 'custom')) {
      const okUser = next?.auth?.username && String(next.auth.username).trim().length > 0
      const okPass = next?.auth?.password && String(next.auth.password).trim().length > 0
      const okPool = Array.isArray(next.pool) ? next.pool.length > 0 : false
      if (!okUser || !okPass || !okPool) {
        ElMessage.error('自定义供应商需填写 代理帐号/代理密码/IP池')
        return
      }
    }
    list[i] = next
    const payload = JSON.parse(JSON.stringify({ proxy: { providers: cleanProvidersForSave(list) } }))
    await appStore.updateConfig(payload as any)
    // 持久化成功后回填最新 _poolText 以便用户继续查看/编辑
    const saved = cleanProvidersForSave(list)
    const cur = saved[i]
    if (cur) {
      const poolText = Array.isArray(cur.pool) ? cur.pool.join('\n') : ''
      ;(next as any)._poolText = poolText
    }
    localConfig.value.proxy.providers = list
    editDialog.visible = false
    ElMessage.success('已保存代理配置')
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

// 将编辑弹窗中的暂存改动（含 _poolText）合并到 localConfig，便于直接点击页面底部“保存配置”
function commitPendingEditToLocal() {
  if (!editDialog?.visible)
    return
  if (!localConfig.value?.proxy?.providers)
    return
  const list = localConfig.value.proxy.providers as any[]
  const i = Number(editDialog.index)
  if (!(i >= 0 && i < list.length))
    return
  const next = JSON.parse(JSON.stringify(editDialog.model || {}))
  if (typeof (next as any)._poolText === 'string') {
    const txt = String((next as any)._poolText || '')
    const arr = txt
      .split(/\r?\n|,/)
      .map((s: string) => s.trim())
      .filter(Boolean)
    next.pool = arr
  }
  delete (next as any)._poolText
  list[i] = next
}

// 代理测试
const proxyTest = reactive({
  visible: false,
  url: 'https://abs1.td.gov.hk/tdab2/tdabs_external/AdminServlet_tchinese',
  running: false,
  result: null as any,
})
function openProxyTestDialog() {
  proxyTest.visible = true
  if (!proxyTest.url)
    proxyTest.url = 'https://abs1.td.gov.hk/tdab2/tdabs_external/AdminServlet_tchinese'
  proxyTest.result = null
}
async function runProxyTest() {
  try {
    proxyTest.running = true
    proxyTest.result = null
    const providerId = (proxyTest as any).providerId || undefined
    const res = await (window as any).api?.proxy?.testUrl(proxyTest.url, providerId)
    if (res?.success) {
      proxyTest.result = res
      ElMessage.success('测试成功')
    }
    else {
      proxyTest.result = res
      ElMessage.error(res?.error || '测试失败')
    }
  }
  catch (e) {
    ElMessage.error(String(e))
  }
  finally {
    proxyTest.running = false
  }
}

async function loadBlacklist() {
  try {
    const res = await window.api.proxy.blacklistList()
    if (res?.success)
      blacklist.value = res.list || []
  }
  catch {}
}

// ===== 本月流量超额标记（quota_exceeded）管理 =====
const quotaMarks = ref<any[]>([])
const quotaLoading = ref(false)
const thisMonth = computed(() => {
  const d = new Date()
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
})
const quotaMarkedSetThisMonth = computed(() => {
  try {
    return new Set((quotaMarks.value || []).filter((m: any) => m && m.month === thisMonth.value).map((m: any) => m.provider_id))
  }
  catch {
    return new Set<string>()
  }
})

async function loadQuotaMarks() {
  try {
    quotaLoading.value = true
    const res = await window.api.proxy.quotaList()
    if (res?.success) {
      quotaMarks.value = Array.isArray(res.list) ? res.list : []
    }
  }
  catch {}
  finally {
    quotaLoading.value = false
  }
}

async function _markProviderQuota(providerId: string) {
  try {
    await ElMessageBox.confirm('确认将该服务商标记为“本月流量超额”吗？标记后将被轮换跳过。', '确认标记', { type: 'warning' })
  }
  catch {
    return
  }
  try {
    await window.api.proxy.quotaMark(providerId, 'manual')
    await loadQuotaMarks()
    ElMessage.success('已标记为本月超额')
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

async function _clearProviderQuota(providerId: string, month?: string) {
  try {
    await window.api.proxy.quotaClear(providerId, month)
    await loadQuotaMarks()
    ElMessage.success('已清除超额标记')
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

async function validateProxyPool() {
  if (validating.value)
    return
  validating.value = true
  try {
    const res = await window.api.proxy.validatePool()
    if (res?.success) {
      await loadBlacklist()
      ElMessage.success(`校验完成：成功 ${res.ok} / 失败 ${res.failed}`)
    }
    else {
      ElMessage.error(res?.error || '校验失败')
    }
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
  finally {
    validating.value = false
  }
}

async function clearBlacklist() {
  try {
    const res = await window.api.proxy.blacklistClear()
    if (res?.success) {
      blacklist.value = []
      ElMessage.success('临时黑名单已清空')
    }
  }
  catch {}
}

// 拉取 WebShare 代理池：若传入对象则先持久化之后再调用后端
async function pullProviderFromWebshare(target: any) {
  try {
    const isObj = typeof target === 'object' && target !== null
    const providerId = isObj ? String(target.id || '') : String(target || '')
    if (!providerId) {
      ElMessage.error('缺少 providerId')
      return
    }
    // 若来自编辑弹窗，先把当前编辑模型合入并持久化
    if (isObj && localConfig.value?.proxy?.providers) {
      const list = [...(localConfig.value.proxy.providers as any[])]
      let idx = list.findIndex((p: any) => p && String(p.id || '') === providerId)
      if (idx === -1)
        idx = list.findIndex((p: any) => p && String(p.id || '') === String(target.__orig_id || ''))
      const next = JSON.parse(JSON.stringify(target))
      if (typeof (next as any)._poolText === 'string') {
        const arr = String((next as any)._poolText || '')
          .split(/\r?\n|,/)
          .map((s: string) => s.trim())
          .filter(Boolean)
        next.pool = arr
        delete (next as any)._poolText
      }
      if (idx >= 0)
        list[idx] = next
      else list.push(next)
      const payload = JSON.parse(JSON.stringify({ proxy: { providers: cleanProvidersForSave(list) } }))
      await appStore.updateConfig(payload as any)
      localConfig.value.proxy.providers = list
    }

    loadingProviderId.value = providerId
    validating.value = true
    const res = await (window as any).api?.proxy?.websharePullList?.(providerId)
    if (res?.success) {
      await loadConfig()
      try {
        if (editDialog.visible) {
          const list = Array.isArray(localConfig.value?.proxy?.providers) ? (localConfig.value!.proxy!.providers as any[]) : []
          const newer = list.find((pp: any) => pp && String(pp.id || '') === providerId)
          if (newer) {
            editDialog.model = JSON.parse(JSON.stringify(newer))
            ;(editDialog.model as any)._poolText = Array.isArray(newer.pool) ? newer.pool.join('\n') : ''
            // 同步 provider.auth 到弹窗
            try {
              if (newer?.auth) {
                if (!editDialog.model.auth)
                  editDialog.model.auth = { username: '', password: '' }
                editDialog.model.auth.username = String(newer.auth.username || '')
                editDialog.model.auth.password = String(newer.auth.password || '')
              }
            }
            catch {}
          }
        }
      }
      catch {}
      ElMessage.success(`已拉取 ${res.count} 条代理`)
    }
    else {
      ElMessage.error(res?.error || '拉取失败')
    }
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
  finally {
    validating.value = false
    loadingProviderId.value = null
  }
}

function _formatBytes(input: number | string): string {
  const n = Number(input || 0)
  if (!Number.isFinite(n) || n < 0)
    return String(input)
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let idx = 0
  let val = n
  while (val >= 1024 && idx < units.length - 1) {
    val /= 1024
    idx++
  }
  return `${val.toFixed(2)} ${units[idx]}`
}

async function _queryProviderStats(p: any) {
  try {
    statsLoadingProviderId.value = p?.id || null
    const res = await window.api.proxy.webshareStatsAggregate(String(p?.id || ''), { plan_id: p?.plan_id || undefined })
    if (res?.success) {
      p._stats = res.data
      p._statsUpdatedAt = Date.now()
      ElMessage.success('已获取 WebShare 用量统计')
    }
    else {
      ElMessage.error(res?.error || '查询用量失败')
    }
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
  finally {
    statsLoadingProviderId.value = null
  }
}

function cleanProvidersForSave(list: any[]): any[] {
  const providers = Array.isArray(list) ? list.map((p: any) => ({ ...(p || {}) })) : []
  providers.forEach((p: any) => {
    delete p._poolText
    delete p._poolPreviewText
    delete p._poolCount
    delete p._poolEditing
    delete p._stats
    delete p._statsUpdatedAt
    // 归一化 auth，避免携带 reactive/Proxy
    if (p?.auth) {
      const u = (p.auth as any).username || ''
      const pw = (p.auth as any).password || ''
      if (!u && !pw)
        delete p.auth
      else
        p.auth = { username: String(u), password: String(pw) }
    }
    // 归一化 pool
    if (Array.isArray(p?.pool))
      p.pool = (p.pool as any[]).map((x: any) => String(x))
    else if (typeof p?.pool === 'string')
      p.pool = String(p.pool).split(/\r?\n|,/).map((s: string) => s.trim()).filter(Boolean)
    // 归一化 enabled
    p.enabled = p?.enabled !== false
  })
  return providers
}

async function enableAllProviders() {
  try {
    if (!localConfig.value?.proxy?.providers)
      return
    const next = (localConfig.value.proxy.providers as any[]).map((p: any) => ({ ...(p || {}), enabled: true }))
    const plain = cleanProvidersForSave(next)
    const payload = JSON.parse(JSON.stringify({ proxy: { providers: plain } }))
    await appStore.updateConfig(payload as any)
    localConfig.value.proxy.providers = next
    ElMessage.success('已启用所有服务商')
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

async function disableExceededProviders() {
  try {
    if (!localConfig.value?.proxy?.providers)
      return
    const marked = quotaMarkedSetThisMonth.value
    if (!marked || marked.size === 0) {
      ElMessage.info('当前没有被标记为“本月超额”的服务商')
      return
    }
    const next = (localConfig.value.proxy.providers as any[]).map((p: any) => ({
      ...(p || {}),
      enabled: marked.has(String(p?.id || '')) ? false : p?.enabled !== false,
    }))
    const plain = cleanProvidersForSave(next)
    const payload = JSON.parse(JSON.stringify({ proxy: { providers: plain } }))
    await appStore.updateConfig(payload as any)
    localConfig.value.proxy.providers = next
    ElMessage.success('已禁用本月超额的服务商')
  }
  catch (e: any) {
    ElMessage.error(String(e?.message || e))
  }
}

// 移除顶层池编辑相关逻辑

// 已移除折叠式内联池编辑方法

// 供应商切换时初始化各自字段
function ensureVendorDefaults(p: any) {
  try {
    const v = (p?.vendor || '').toLowerCase()
    if (v === 'webshare') {
      // 协议默认 HTTP，名称根据免费/付费与帐号生成
      if (!p.protocol)
        p.protocol = 'http'
      if (typeof p.is_free !== 'boolean')
        p.is_free = false
      updateWebshareLabel(p)
    }
  }
  catch {}
}

function updateWebshareLabel(p: any) {
  try {
    const isFree = !!p?.is_free
    const vendor = 'WebShare'
    p.label = `${vendor}-${isFree ? '免费代理' : '付费代理'}`
  }
  catch {}
}
</script>

<template>
  <div v-if="localConfig.value" class="config-page">
    <el-card shadow="never">
      <template #header>
        <div>
          <h2 class="mb-2 text-2xl text-gray-800 font-bold">
            配置管理
          </h2>
          <p class="text-gray-600">
            管理应用配置和偏好设置
          </p>
        </div>
      </template>
      <el-tabs v-model="activeTab">
        <!-- 基础配置 -->
        <el-tab-pane label="基础配置" name="basic">
          <el-card shadow="never">
            <div class="form-section">
              <div class="form-section-title">
                网络配置
              </div>
              <el-form label-width="150px" class="two-col-form">
                <el-form-item label="请求超时(秒)">
                  <el-input-number
                    v-model="localConfig.value.network.request_timeout_seconds"
                    :min="5"
                    :max="60"
                  />
                </el-form-item>
                <el-form-item label="最小请求间隔(秒)">
                  <el-input-number
                    v-model="localConfig.value.network.global_min_interval_seconds"
                    :min="0.5"
                    :max="10"
                    :step="0.1"
                  />
                </el-form-item>
              </el-form>
            </div>

            <div class="form-section">
              <div class="form-section-title">
                预约配置
              </div>
              <el-form label-width="150px" class="two-col-form">
                <el-form-item label="可用窗口天数">
                  <el-input-number
                    v-model="localConfig.value.booking.available_window_days"
                    :min="30"
                    :max="120"
                  />
                </el-form-item>
                <el-form-item label="默认服务类型">
                  <el-select v-model="localConfig.value.booking.service_type">
                    <el-option label="免试签发驾驶执照" value="DI" />
                  </el-select>
                </el-form-item>
                <el-form-item label="默认办理地点">
                  <el-select v-model="localConfig.value.booking.default_office_code">
                    <el-option label="香港牌照事务处" value="HKLO" />
                  </el-select>
                </el-form-item>
              </el-form>
            </div>
          </el-card>
        </el-tab-pane>

        <!-- 日志配置 -->
        <el-tab-pane label="日志配置" name="logging">
          <el-card class="config-card" shadow="never">
            <div class="form-section">
              <div class="form-section-title">
                日志设置
              </div>
              <el-form label-width="150px" class="two-col-form">
                <el-form-item label="日志级别">
                  <el-select v-model="localConfig.value.logging.log_level">
                    <el-option label="DEBUG" value="DEBUG" />
                    <el-option label="INFO" value="INFO" />
                    <el-option label="WARN" value="WARN" />
                    <el-option label="ERROR" value="ERROR" />
                  </el-select>
                </el-form-item>
                <el-form-item label="控制台输出">
                  <el-switch v-model="localConfig.value.logging.console_output" />
                </el-form-item>
                <el-form-item label="文件输出">
                  <el-switch v-model="localConfig.value.logging.file_output" />
                </el-form-item>
                <el-form-item label="保存HTML">
                  <el-switch v-model="localConfig.value.logging.save_html" />
                </el-form-item>
                <el-form-item label="保存快照/截图">
                  <el-switch v-model="localConfig.value.logging.save_snapshots" />
                </el-form-item>
                <el-form-item label="日志保留时间">
                  <el-input v-model="localConfig.value.logging.log_retention" />
                </el-form-item>
                <el-form-item label="日志目录">
                  <el-button @click="openLogsDir">
                    打开日志目录
                  </el-button>
                </el-form-item>
              </el-form>
            </div>
          </el-card>
        </el-tab-pane>

        <!-- 代理配置 -->
        <el-tab-pane label="代理配置" name="proxy">
          <el-card class="config-card" shadow="never">
            <div class="form-section">
              <div class="form-section-title">
                代理基础设置
              </div>
              <div class="mb-2 text-gray-600">
                <div>提示：</div>
                <ul class="list-disc pl-5">
                  <li>必须开启“启用代理”，自动化才会走代理。</li>
                  <li>仅使用“多服务商”进行代理配置，已移除单一提供商与顶层池概念。</li>
                </ul>
              </div>
              <el-form label-width="160px" class="two-col-form">
                <el-form-item label="启用代理">
                  <el-switch v-model="localConfig.value.proxy.enabled" />
                </el-form-item>
              </el-form>
            </div>

            <div class="form-section">
              <div class="form-section-title">
                轮换策略
              </div>
              <div class="mb-2 text-gray-600">
                <div>提示：</div>
                <ul class="list-disc pl-5">
                  <li>“每会话轮换”建议配合粘性时间使用；“每请求轮换”更激进，带来更高流量。</li>
                </ul>
              </div>
              <el-form label-width="160px">
                <el-form-item label="轮换模式">
                  <el-select v-model="localConfig.value.proxy.rotate_mode">
                    <el-option label="每会话轮换" value="per_session" />
                    <el-option label="每请求轮换" value="per_request" />
                  </el-select>
                </el-form-item>
                <el-form-item label="粘性时间(分钟)">
                  <el-input-number v-model="localConfig.value.proxy.sticky_minutes" :min="0" :max="120" />
                </el-form-item>
                <el-form-item label="轮换触发错误">
                  <el-input
                    v-model="rotateErrorsText"
                    type="textarea"
                    :rows="4"
                    placeholder="每行一个，如: 407\nERR_TUNNEL_CONNECTION_FAILED\nECONNRESET\nETIMEDOUT"
                  />
                </el-form-item>
                <el-form-item label="最大并发会话">
                  <el-input-number v-model="localConfig.value.proxy.max_concurrent_sessions" :min="0" :max="200" />
                  <template #description>
                    <span class="text-gray-500">0 表示不限制（不排队）</span>
                  </template>
                </el-form-item>
              </el-form>
            </div>

            <div class="form-section">
              <div class="form-section-title">
                多服务商（providers）
              </div>
              <div class="mb-2 text-gray-600">
                <div>提示：</div>
                <ul class="list-disc pl-5">
                  <li>右侧开关控制该服务商是否参与轮换（需先开启“启用代理”）。</li>
                  <li>WebShare 需提供 API Token；支持通过“拉取代理池”从列表接口获取。</li>
                  <li>WebShare 动态住宅池可能出现相同 <code>ip:port</code>，由用户名后缀区分会话。</li>
                </ul>
              </div>
              <div class="mb-3">
                <el-button type="primary" @click="openAddProviderDialog">
                  新增代理
                </el-button>
                <el-button class="ml-2" @click="enableAllProviders">
                  一键启用所有服务商
                </el-button>
                <el-button class="ml-2" type="warning" @click="disableExceededProviders">
                  一键禁用已超流量服务商
                </el-button>
              </div>
              <div class="mb-3 flex items-center space-x-3">
                <el-input v-model="providerFilter" placeholder="搜索ID或名称" clearable style="max-width: 260px;" />
                <div class="text-gray-600">
                  共 {{ providersFiltered.length }} 个
                </div>
              </div>
              <el-table :data="providersPaged" size="small" style="width: 100%">
                <el-table-column label="启用" width="90">
                  <template #default="{ row, $index }">
                    <el-switch :model-value="row.enabled !== false" @change="(val:boolean) => onToggleProvider(row, $index, val)" />
                  </template>
                </el-table-column>
                <el-table-column prop="label" label="名称" min-width="160">
                  <template #default="{ row }">
                    {{ row.label || row.id }}
                  </template>
                </el-table-column>
                <el-table-column prop="vendor" label="供应商" width="110" />
                <el-table-column prop="account" label="帐号" min-width="180" />
                <el-table-column prop="type" label="类型" width="120">
                  <template #default="{ row }">
                    {{ (String(row.type || '').toLowerCase() === 'residential') ? '住宅代理' : (String(row.type || '').toLowerCase() === 'datacenter' ? '数据中心代理' : '动态池') }}
                  </template>
                </el-table-column>
                <el-table-column prop="protocol" label="协议" width="100" />
                <el-table-column label="池条数" width="100">
                  <template #default="{ row }">
                    {{ Array.isArray(row.pool) ? row.pool.length : 0 }}
                  </template>
                </el-table-column>
                <el-table-column label="操作" width="200" fixed="right">
                  <template #default="{ row, $index }">
                    <el-button size="small" type="primary" link @click="openEditProvider(row, $index)">
                      编辑
                    </el-button>
                    <el-divider direction="vertical" />
                    <el-button size="small" type="danger" link @click="() => removeProvider($index)">
                      删除
                    </el-button>
                  </template>
                </el-table-column>
              </el-table>
              <div class="mt-3 flex items-center justify-end">
                <el-pagination
                  background
                  small
                  layout="prev, pager, next, ->, total"
                  :total="providersFiltered.length"
                  :page-size="providerPageSize"
                  :current-page="providerCurrentPage"
                  @current-change="(p:number) => providerCurrentPage = p"
                />
              </div>
            </div>

            <div class="form-section">
              <div class="form-section-title">
                代理校验（手动触发，位于尾部）
              </div>
              <div class="mb-2 text-gray-600">
                <div>提示：</div>
                <ul class="list-disc pl-5">
                  <li>仅在点击“校验代理池”时进行连通性校验（HEAD 请求）。</li>
                  <li>失败的代理会进入临时黑名单，不影响其它代理使用。</li>
                  <li>黑名单 TTL 可在配置中设置（默认 60 分钟），到期自动恢复。</li>
                </ul>
              </div>
              <div class="mb-2 text-gray-600">
                当前校验 URL：
                <el-link :underline="false" :href="(localConfig.value?.proxy?.validation?.test_url || 'https://www.gov.hk/')" target="_blank">
                  {{ localConfig.value?.proxy?.validation?.test_url || 'https://www.gov.hk/' }}
                </el-link>
              </div>
              <div class="mb-3 flex items-center space-x-3">
                <el-button type="primary" :loading="validating" @click="validateProxyPool">
                  校验代理池
                </el-button>
                <el-button @click="loadBlacklist">
                  刷新黑名单
                </el-button>
                <el-button type="warning" @click="clearBlacklist">
                  清空黑名单
                </el-button>
                <el-button class="ml-2" @click="openProxyTestDialog">
                  测试代理（运输署）
                </el-button>
              </div>
              <el-table v-if="blacklist.length" :data="blacklist" size="small" style="width: 100%">
                <el-table-column prop="server" label="代理" width="260" />
                <el-table-column prop="reason" label="原因" />
                <el-table-column label="到期">
                  <template #default="{ row }">
                    {{ new Date(row.until).toLocaleString() }}
                  </template>
                </el-table-column>
              </el-table>
              <div v-else class="text-gray-500">
                当前没有临时黑名单项
              </div>
            </div>
          </el-card>
        </el-tab-pane>
      </el-tabs>

      <template #footer>
        <el-affix position="bottom" :offset="48">
          <div class="config-footer-affix">
            <!-- 操作按钮 -->
            <div class="config-footer-inner flex justify-end space-x-4">
              <el-button @click="resetConfig">
                重置配置
              </el-button>
              <el-button @click="loadConfig">
                重新加载
              </el-button>
              <el-button type="primary" :disabled="!isDirty" :loading="saving" @click="saveConfig">
                保存配置
              </el-button>
            </div>
          </div>
        </el-affix>
      </template>
    </el-card>
  </div>
  <div v-else class="config-page">
    <div class="h-64 flex items-center justify-center">
      <el-icon class="is-loading mr-2">
        <Loading />
      </el-icon>
      <span>正在加载配置...</span>
    </div>
  </div>

  <!-- 代理测试对话框 -->
  <el-dialog v-model="proxyTest.visible" title="测试代理可用性" width="780px">
    <div class="mb-3 flex flex-wrap items-center gap-3">
      <el-input v-model="proxyTest.url" placeholder="测试地址（可修改）" clearable style="width: 420px" />
      <el-select v-model="(proxyTest as any).providerId" placeholder="选择代理池(Provider)" clearable style="width: 240px">
        <el-option value="top" label="顶层池(top)" />
        <el-option
          v-for="pp in (localConfig.value?.proxy?.providers || [])"
          :key="pp.id"
          :label="pp.label || pp.id"
          :value="pp.id"
        />
      </el-select>
      <el-button type="primary" :loading="proxyTest.running" @click="runProxyTest">
        开始测试
      </el-button>
    </div>

    <div v-if="proxyTest.result" class="text-sm space-y-1">
      <div>
        连通状态：<b>{{ proxyTest.result?.test?.status ?? '-' }}</b>
      </div>
      <div>
        出口IP：<b>{{ proxyTest.result?.ip?.address ?? '-' }}</b>
        <span v-if="proxyTest.result?.ip?.source" class="text-gray-500">（来源：{{ proxyTest.result.ip.source }}）</span>
      </div>
      <div>
        代理信息：{{ proxyTest.result?.proxy?.server || '-' }}
        <span v-if="proxyTest.result?.proxy?.provider_label" class="text-gray-500">[{{ proxyTest.result.proxy.provider_label }}]</span>
        <span v-else-if="proxyTest.result?.proxy?.provider_id" class="text-gray-500">[{{ proxyTest.result.proxy.provider_id }}]</span>
      </div>
      <div v-if="proxyTest.result?.ip?.raw" style="white-space: pre-wrap; word-break: break-all;" class="border rounded bg-gray-50 p-2">
        原始响应：{{ proxyTest.result.ip.raw }}
      </div>
      <div v-if="proxyTest.result?.error" class="text-red-600">
        错误：{{ proxyTest.result.error }}
      </div>
    </div>

    <template #footer>
      <el-button @click="proxyTest.visible = false">
        关闭
      </el-button>
    </template>
  </el-dialog>

  <!-- 新增代理对话框 -->
  <el-dialog v-model="addDialog.visible" title="新增代理" width="520px">
    <el-form label-width="120px">
      <el-form-item label="供应商">
        <el-select v-model="addDialog.model.vendor" style="width: 220px">
          <el-option value="webshare" label="WebShare" />
          <el-option value="custom" label="自定义" />
        </el-select>
      </el-form-item>
      <template v-if="(addDialog.model.vendor || '').toLowerCase() === 'webshare'">
        <el-form-item label="登录账号">
          <el-input v-model="addDialog.model.account" placeholder="WebShare 登录账号(邮箱)" />
        </el-form-item>
        <el-form-item label="API Token">
          <el-input v-model="addDialog.model.api_key" type="password" show-password placeholder="WebShare API Token" />
        </el-form-item>
        <el-form-item label="是否免费">
          <el-switch v-model="addDialog.model.is_free" />
        </el-form-item>
      </template>
      <template v-else>
        <el-form-item label="代理帐号">
          <el-input v-model="addDialog.model.proxyUser" placeholder="必填" />
        </el-form-item>
        <el-form-item label="代理密码">
          <el-input v-model="addDialog.model.proxyPass" type="password" show-password placeholder="必填" />
        </el-form-item>
        <el-form-item label="IP池">
          <el-input v-model="addDialog.model.poolText" type="textarea" :rows="6" placeholder="每行一个: ip:port 或 ip:port:username:password（必填）" />
        </el-form-item>
      </template>
      <el-form-item label="代理类型">
        <el-select v-model="addDialog.model.type" style="width: 220px">
          <el-option label="数据中心代理" value="datacenter" />
          <el-option label="住宅代理" value="residential" />
          <el-option label="动态池" value="dynamic_pool" />
        </el-select>
      </el-form-item>
      <el-form-item label="协议">
        <el-select v-model="addDialog.model.protocol" style="width: 220px">
          <el-option label="HTTP" value="http" />
          <el-option label="HTTPS" value="https" />
          <el-option label="SOCKS5" value="socks5" />
        </el-select>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="addDialog.visible = false">
        取消
      </el-button>
      <el-button type="primary" @click="confirmAddProvider">
        确定
      </el-button>
    </template>
  </el-dialog>

  <!-- 编辑代理对话框 -->
  <el-dialog v-model="editDialog.visible" title="编辑代理" width="640px">
    <el-form label-width="120px">
      <el-form-item label="ID">
        <el-input v-model="editDialog.model.id" />
      </el-form-item>
      <el-form-item label="名称">
        <el-input v-model="editDialog.model.label" />
      </el-form-item>
      <el-form-item label="供应商">
        <el-select v-model="editDialog.model.vendor" style="width: 220px" @change="() => ensureVendorDefaults(editDialog.model)">
          <el-option value="webshare" label="WebShare" />
          <el-option value="custom" label="自定义" />
        </el-select>
      </el-form-item>
      <template v-if="(editDialog.model.vendor || '').toLowerCase() === 'webshare'">
        <el-form-item label="登录账号">
          <el-input v-model="editDialog.model.account" @change="() => updateWebshareLabel(editDialog.model)" />
        </el-form-item>
        <el-form-item label="API Token">
          <el-input v-model="editDialog.model.api_key" type="password" show-password />
        </el-form-item>
        <el-form-item label="是否免费">
          <el-switch v-model="editDialog.model.is_free" @change="() => updateWebshareLabel(editDialog.model)" />
        </el-form-item>
      </template>
      <el-form-item label="代理类型">
        <el-select v-model="editDialog.model.type" style="width: 220px">
          <el-option label="数据中心代理" value="datacenter" />
          <el-option label="住宅代理" value="residential" />
          <el-option label="动态池" value="dynamic_pool" />
        </el-select>
      </el-form-item>
      <el-form-item label="协议">
        <el-select v-model="editDialog.model.protocol" style="width: 220px">
          <el-option label="HTTP" value="http" />
          <el-option label="HTTPS" value="https" />
          <el-option label="SOCKS5" value="socks5" />
        </el-select>
      </el-form-item>
      <el-form-item label="代理帐号">
        <el-input v-model="editDialog.model.auth.username" />
      </el-form-item>
      <el-form-item label="代理密码">
        <el-input v-model="editDialog.model.auth.password" type="password" show-password />
      </el-form-item>
      <el-form-item label="IP池">
        <el-input v-model="(editDialog.model as any)._poolText" type="textarea" :rows="6" placeholder="每行一个: ip:port 或 ip:port:username:password" />
        <template #description>
          <span class="text-gray-500">保存时将覆盖为行内数组</span>
        </template>
      </el-form-item>
      <div class="mb-2">
        <el-button v-if="(editDialog.model.vendor || '').toLowerCase() === 'webshare' && editDialog.model.api_key" :loading="validating && (loadingProviderId === editDialog.model.id)" @click="() => pullProviderFromWebshare(editDialog.model)">
          拉取代理池
        </el-button>
        <el-button :loading="statsLoadingProviderId === editDialog.model.id" :disabled="!(editDialog.model.api_key)" @click="() => _queryProviderStats(editDialog.model)">
          查询用量
        </el-button>
      </div>
    </el-form>
    <template #footer>
      <el-button @click="editDialog.visible = false">
        取消
      </el-button>
      <el-button type="primary" @click="confirmEditProvider">
        保存
      </el-button>
    </template>
  </el-dialog>
</template>

<style scoped>
.config-page {
  width: 100%;
  max-width: none;   /* 全宽响应式 */
}

.config-tabs :deep(.el-tab-pane) {
  padding-top: 20px;
}

.config-footer-inner {
  width: 100%;
  max-width: none;
  margin: 0 auto;
  padding: 0 16px;
  box-sizing: border-box;
}

/* 两列自适应表单：宽屏并排显示，窄屏单列 */
.two-col-form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 24px;
}
.two-col-form :deep(.el-form-item) {
  width: 100%;
}
@media (min-width: 1280px) {
  .two-col-form :deep(.el-form-item) {
    width: calc(50% - 12px);
  }
}

.config-footer-affix {
  width: 100%;
  background: var(--el-bg-color);
  border-top: 1px solid var(--el-border-color);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.04);
  padding: 10px 0;
}
</style>
